package com.webrtc.audioprocessing;

import android.app.AlertDialog;
import android.content.Context;
import android.media.AudioManager;
import android.util.Log;

public class AudioProcessing {

    private Apm _apm;
    private ApmViewModel vm;
    private Context context;
    private Counters counter;

    private int _nsLevel = 2;
    private int _agcLevel = 0;
    private int _sendCount = 0;
    private int _aecPCLevel = 2;
    private int _receveCount = 0;

    private int _aecMobileLevel = 2;

    public static final int CHANNELS = 1;

    public static final int SAMPLE_RATE = 16000;
    public static final int BITS_PER_SAMPLE = 16;

    private static final int AEC_BUFFER_SIZE_MS = 10;
    private static final int CALLBACK_BUFFER_SIZE_MS = 10;
    public static final int BUFFERS_PER_SECOND = 1000 / CALLBACK_BUFFER_SIZE_MS;

    private static final int AEC_LOOP_COUNT = CALLBACK_BUFFER_SIZE_MS / AEC_BUFFER_SIZE_MS;

    public AudioProcessing(Context context, ApmViewModel apmViewModel, Counters counter) {
        this.context = context;
        this.counter = counter;
        vm = apmViewModel;
        Log.d("abcd", vm.toString());

        Start();
    }

    void getLevels() {
        if (vm.getAecPCMode0()) {
            _aecPCLevel = 0;
        } else if (vm.getAecPCMode1()) {
            _aecPCLevel = 1;
        } else if (vm.getAecPCMode2()) {
            _aecPCLevel = 2;
        }

        if (vm.getAecMobileMode0()) {
            _aecMobileLevel = 0;
        } else if (vm.getAecMobileMode1()) {
            _aecMobileLevel = 1;
        } else if (vm.getAecMobileMode2()) {
            _aecMobileLevel = 2;
        } else if (vm.getAecMobileMode3()) {
            _aecMobileLevel = 3;
        } else if (vm.getAecMobileMode4()) {
            _aecMobileLevel = 4;
        }

        if (vm.getNsMode0()) {
            _nsLevel = 0;
        } else if (vm.getNsMode1()) {
            _nsLevel = 1;
        } else if (vm.getNsMode2()) {
            _nsLevel = 2;
        } else if (vm.getNsMode3()) {
            _nsLevel = 3;
        }

        if (vm.getAgcMode0()) {
            _agcLevel = 0;
        } else if (vm.getAgcMode1()) {
            _agcLevel = 1;
        } else if (vm.getAgcMode2()) {
            _agcLevel = 2;
        }
    }

    public void Start() {
        getLevels();

        int ret = -1;
        try {

            _apm = new Apm(vm.getAecExtendFilter(), vm.getSpeechIntelligibilityEnhance(), vm.getDelayAgnostic(), vm.getBeamForming(),
                    vm.getNextGenerationAEC(), vm.getExperimentalNS(), vm.getExperimentalAGC());

            ret = _apm.HighPassFilter(vm.getHighPassFilter());

            if (vm.getAecPC()) {
                ret = _apm.AECClockDriftCompensation(false);
                ret = _apm.AECSetSuppressionLevel(Apm.AEC_SuppressionLevel.values()[_aecPCLevel]);
                ret = _apm.AEC(true);
            } else if (vm.getAecMobile()) {
                ret = _apm.AECMSetSuppressionLevel(Apm.AECM_RoutingMode.values()[_aecMobileLevel]);
                ret = _apm.AECM(true);
            }

            ret = _apm.NSSetLevel(Apm.NS_Level.values()[_nsLevel]);
            ret = _apm.NS(vm.getNs());

            ret = _apm.VAD(vm.getVad());

            if (vm.getAgc()) {
                ret = _apm.AGCSetAnalogLevelLimits(0, 255);
                ret = _apm.AGCSetMode(Apm.AGC_Mode.values()[_agcLevel]);
                ret = _apm.AGCSetTargetLevelDbfs(vm.getAgcTargetLevelInt());
                ret = _apm.AGCSetcompressionGainDb(vm.getAgcCompressionGainInt());
                ret = _apm.AGCEnableLimiter(true);
                ret = _apm.AGC(true);
            }
        } catch (Exception ex) {
            new AlertDialog.Builder(context).setTitle("System hint")
                    .setMessage(ex.getMessage())
                    .show();
            return;
        }

        try {
            vm.setStart(true);
        } catch (Exception ex) {
            ex.printStackTrace();
        }

    }

    public void onSpeaker(boolean on) {
        AudioManager audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
        audioManager.setMode(AudioManager.MODE_IN_COMMUNICATION);
        audioManager.setSpeakerphoneOn(on);
    }


    public void onDestroy() {
        vm.setStart(false);

        if (_apm != null) {
            _apm.close();
        }

        _receveCount = 0;
        _sendCount = 0;
    }

    public void process(short[] processBuffer, int readSize) { // 16K, mono, 16bits
        int out_analog_level = 200;
        try {
            if (readSize == processBuffer.length) {
                for (int i = 0; i < AEC_LOOP_COUNT; ++i) {
                    int processBufferOffSet = i * processBuffer.length / AEC_LOOP_COUNT;

                    _apm.SetStreamDelay(vm.getAceBufferDelayMs());
                    if (vm.getAgc()) {
                        _apm.AGCSetStreamAnalogLevel(out_analog_level);
                    }

                    _apm.ProcessCaptureStream(processBuffer, processBufferOffSet);

                    if (vm.getAgc()) {
                        out_analog_level = _apm.AGCStreamAnalogLevel();
//                                Log.i("AGC", out_analog_level + "");
                    }

                    if (vm.getVad()) {
                        if (!_apm.VADHasVoice()) continue;
                    }
                }

            } else {
//                        Log.e("record", "AudioRecord.read failed: " + bytesRead);
            }
        } catch (Exception ex) {
            if (vm.getStart()) ;
            ex.printStackTrace();

        }
    }
}
